<?php
declare(strict_types=1);
namespace Aincrid\MySwoole;

use Aincrid\MySwoole\Facade\Container;

/**
 * @deprecated version
 */
class Router
{
    protected ?Router $parent = null;

    protected string $path = '';

    protected int $deep = 0;

    protected string $method = '';

    protected string|\Closure $handler = '';

    protected array $middlewares = [];

    protected bool $isEnd = false;

    // deep 为索引，值为这一代的数组
    protected array $nexts = [];

    //handler 命名空间
    protected string $namespace = '';

    protected array $fullurl = [];

    public function __construct(string $path = '', int $deep = 0, string $handler = '')
    {
        $this->path = $path;
        $this->deep = $deep;
        $this->handler = $handler;
    }


    public function group(string $path, \Closure $callback): Router
    {
        $router = Router::insertAfter($this, $path);
        $callback($router);
        return $router;
    }


    public function middleware(array $middleware): Router
    {
        array_push($this->middlewares, ...$middleware);
        return $this;
    }



    public function addRoute(string $method, string $paths, $handler): Router
    {
        $curNode = $this;

        $paths = trim($paths, '/');

        if (empty($paths)) {
            $curNode->method = $method;
            $curNode->handler = $handler;
            $curNode->isEnd = true;
            return $curNode;
        }

        $pathArrs = explode('/', $paths);

        foreach ($pathArrs as $index => $path) {
            if ($path != '') {
                if ($index + 1 == count($pathArrs)) {
                    $curNode = $this->insertAfter($curNode, $path, $method, $handler);
                } else {
                    $curNode = $this->insertAfter($curNode, $path);
                }
            }
        }

        return $curNode;
    }


    public function get(string $paths, $handler): Router
    {
        return $this->addRoute('get', $paths, $handler);
    }



    public function namespace (string $namespace)
    {
        $this->namespace = $namespace;
        return $this;
    }




    protected static function insertAfter(Router $node, string $path, string $method = '', string|\Closure $handler = ''): Router
    {
        $path = trim($path, '/');
        $deep = $node->deep + 1;
        $routerItem = $node->findNodeInDeep($node, $deep, $path);
        // 不存在创建路由
        if (!$routerItem) {
            $curPathRouterItem = new Router($path, $deep);
            $curPathRouterItem->parent = $node;
            $routerItem = $curPathRouterItem;
        }
        // 存在会重新设置路由
        if (!empty($handler)) {
            $routerItem->isEnd = true;
            $routerItem->handler = $handler;
            $routerItem->method = $method;
        } else {
            $routerItem->isEnd = false;
        }
        $node->nexts[$deep][] = $routerItem;
        return $routerItem;
    }


    protected function findNodeInDeep(Router $node, int $deep, string $path): Router|bool
    {
        $arrs = $node->nexts[$deep] ?? [];
        if (!empty($arrs)) {
            foreach ($arrs as $node) {
                if ($node->deep == $deep && $node->path == $path) {
                    return $node;
                }
            }
        }
        return false;
    }


    public function dispatch(string $url, Request $request, Response $response)
    {
        $node = $this->findNode($url);
        if (!$node) {
            $response->httpNotFound();
        } else {
            $handlerArr = $node->nodeBuildUrl();
            $handler = $handlerArr['handler'];
            Container::get(Container::class)->invoke($handler, ['request' => $request, 'response' => $response]);
        }
    }


    public function nodeBuildUrl(): array
    {
        $curNode = $this;
        $pathArr[] = $curNode->path;
        $middlewares = $curNode->middlewares;
        $handler = $curNode->handler;
        while (true) {
            if (is_null($curNode->parent)) {
                break;
            }
            if (!empty($curNode->parent->namespace)) {
                if (!is_callable($handler)) {
                    $handler = trim($curNode->parent->namespace, '\\') . '\\' . $handler;
                }
            }

            if (!empty($curNode->parent->middlewares)) {
                array_push($middlewares, ...$curNode->parent->middlewares);
            }

            array_unshift($pathArr, $curNode->parent->path);

            $curNode = $curNode->parent;
        }
        return ['path_arr' => $pathArr, 'handler' => $handler, 'middleware' => array_reverse($middlewares)];
    }


    protected function findNode(string $url): bool|Router
    {
        $url = trim($url, '/');
        $pathsArr = explode('/', $url);
        $curNode = $this;
        foreach ($pathsArr as $index => $path) {
            $deep = $index + 1;
            $curNode = $this->findNodeInDeep($curNode, $deep, $path);
            if (!$curNode) {
                return false;
            }
        }
        if (!$curNode->isEnd) {
            return false;
        }
        return $curNode;
    }
}